<?php
// +----------------------------------------------------------------------
// | 未处理数据统计服务
// +----------------------------------------------------------------------

namespace common\service;

use common\model\CountPendingModel;
use common\model\EntityModel;
use common\model\StepModel;
use common\model\TaskModel;
use think\module\Module;

class CountPendingService
{

    /**
     * 未处理数据统计服务
     *
     * 数据表涉及字段
     * id: 主键
     * type: 数据统计类型  assign_task（任务分配）、review_submit（任务审核提交）、review_submit_feedback（任务审核反馈审核）
     * project_id: 所属项目
     * episode_id: 所属集数
     * step_id: 所属工序，工序分类可以根据这个来统计
     * number: 统计数量
     * updated: 更新时间
     * created: 创建时间
     */

    /**
     * 更新数据
     * @param $existId
     * @param $mode
     * @param $number
     */
    private function baseUpdateData($existId, $mode, $number)
    {
        $countPendingModel = model(CountPendingModel::class);

        if ($mode === "add") {
            $countPendingModel->execute("update count_pending set number = number + {$number} where id = {$existId}");
        } else {
            $countPendingModel->execute("update count_pending set number = IF(number<{$number},0,number-{$number}) where id = {$existId}");
        }
    }

    /**
     * 新增数据
     * @param $data
     * @param $filter
     */
    private function baseAddNewData($data, $filter)
    {
        try {
            model(CountPendingModel::class)->addItem($data);
        } catch (\Throwable $e) {
            // 有异常再尝试一次更新
            $existId = model(CountPendingModel::class)->where($filter)->getField('id');
            if ($existId > 0) {
                $this->baseUpdateData($existId, 'add', $data['number']);
            }
        }
    }

    /**
     * 新增数据基础方法或者减少数据基础方法
     * @param int $taskId
     * @param string $mode
     * @param string $type
     */
    public function baseAddOrSubTaskData(int $taskId, string $mode, string $type)
    {

        /**
         * 获取任务基础数据
         * project_id 项目id
         * initial_episode_code 初始集数（在队列处理时候在查询）
         * entity_id 实体id
         * entity_module_id 实体所属模块id
         * step_id 工序id
         */
        $task = model(TaskModel::class)->field('id,project_id,step_id,entity_id')
            ->where([
                'step_type' => 'step',
                'id' => $taskId
            ])
            ->find();

        if (empty($task)) {
            return;
        }

        // 数据类型
        $taskData = [
            'type' => $type,
            'number' => 1,
            'project_id' => $task['project_id'],
            'step_id' => $task['step_id'],
        ];

        // 获取任务集数id
        $taskData['episode_id'] = 0;
        $initialEpisodeCode = model(EntityModel::class)->where(['id' => $task['entity_id']])->getField('initial_episode_code');
        if (!empty($initialEpisodeCode)) {
            $episodeId = model(EntityModel::class)->where(['project_id' => $task['project_id'], 'module_id' => Module::$moduleDictData['module_index_by_code']['episode']['id'], 'code' => $initialEpisodeCode])->getField('id');
            if ($episodeId > 0) {
                $taskData['episode_id'] = $episodeId;
            }
        }

        // 查询当前数据是否已经存在
        $filter = [
            'type' => $taskData['type'],
            'project_id' => $taskData['project_id'],
            'episode_id' => $taskData['episode_id'],
            'step_id' => $taskData['step_id']
        ];

        $existData = model(CountPendingModel::class)
            ->field('id,number')
            ->where($filter)
            ->find();

        if (!empty($existData)) {
            // 存在忽略 add 操作
            if ($mode === 'sub') {
                if ($existData['number'] > 0) {
                    $this->baseUpdateData($existData['id'], 'sub', 1);
                }
            } else {
                // number递增
                $this->baseUpdateData($existData['id'], 'add', 1);
            }
        } else {
            // 不存在直接忽略 sub 操作
            if ($mode === 'add') {
                // 有唯一索引保证不会多增加
                $this->baseAddNewData($taskData, $filter);
            }
        }
    }

    /**
     * 待分配任务，清单发布后增加计数
     * @param $taskId
     */
    public function assignTaskAdd($taskId)
    {
        if (empty($taskId)) {
            return;
        }

        $this->baseAddOrSubTaskData($taskId, 'add', 'assign_task');
    }

    /**
     * 待分配任务，任务分配完成减少计数
     * @param $taskId
     */
    public function assignTaskSub($taskId)
    {
        if (empty($taskId)) {
            return;
        }

        $this->baseAddOrSubTaskData($taskId, 'sub', 'assign_task');
    }

    /**
     * 提交审核，组长审核完任务
     * @param $taskId
     */
    public function reviewSubmitAdd($taskId)
    {
        if (empty($taskId)) {
            return;
        }

        $this->baseAddOrSubTaskData($taskId, 'add', 'review_submit');
    }

    /**
     * 提交审核，制片提交审核
     */
    public function reviewSubmitSub($taskId)
    {
        if (empty($taskId)) {
            return;
        }

        $this->baseAddOrSubTaskData($taskId, 'sub', 'review_submit');
    }

    /**
     * 审核有反馈待处理、审核不通过后
     */
    public function reviewSubmitFeedbackAdd($taskId)
    {
        if (empty($taskId)) {
            return;
        }

        $this->baseAddOrSubTaskData($taskId, 'add', 'review_submit_feedback');
    }

    /**
     * 审核有反馈待处理、制片接受或者拒绝工单
     */
    public function reviewSubmitFeedbackSub($taskId)
    {
        if (empty($taskId)) {
            return;
        }

        $this->baseAddOrSubTaskData($taskId, 'sub', 'review_submit_feedback');
    }


    /**
     * 获取统计数据
     * @param $type
     * @param $projectId
     * @param array $filterParam
     * @return array
     */
    public function getTaskCountData($type, $projectId, array $filterParam)
    {
        /**
         * 过滤条件
         * 1、根据集数 episode_id 过滤
         * 2、根据 step_category_id 工序分类id
         * 3、根据 step_id 工序id
         */

        $categoryStepIds = [];
        if (!empty($filterParam['step_category_id'])) {
            // 无过滤条件则
            $categoryStepData = model(StepModel::class)
                ->field('step_category_id,id')
                ->where(['step_category_id' => ['IN', join(',', $filterParam['step_category_id'])]])
                ->select();

            $categoryStepDataDict = [];
            foreach ($categoryStepData as $categoryStepItem) {
                $categoryStepDataDict[$categoryStepItem['id']] = $categoryStepItem['step_category_id'];
                if (!in_array($categoryStepItem['id'], $categoryStepIds)) {
                    $categoryStepIds[] = $categoryStepItem['id'];
                }
            }
        }

        if (!empty($filterParam['step_id'])) {
            $categoryStepIds = array_unique(array_merge($categoryStepIds, $filterParam['step_id']));
        }

        // 组装过滤条件
        $filter = [
            'type' => $type,
            'project_id' => $projectId,
            'number' => ['NEQ', 0]
        ];
        if (!empty($filterParam['episode_id'])) {
            $filter['episode_id'] = ['IN', join(',', $filterParam['episode_id'])];
        }

        if (!empty($categoryStepIds)) {
            $filter['step_id'] = ['IN', join(',', $categoryStepIds)];
        }

        $countPendingData = model(CountPendingModel::class)
            ->field('id,episode_id,step_id,number')
            ->where($filter)
            ->select();

        /**
         * 按以下几个维度来返回统计数据
         * 1、全部
         * 2、按集数
         * 3、工序分类
         * 4、工序
         */
        $countData = [
            'total' => 0,
            'episodes' => [],
            'step_category' => [],
            'step' => []
        ];
        if (!empty($countPendingData)) {
            foreach ($countPendingData as $countPendingItem) {

                // 总数统计自增
                $countData['total'] += $countPendingItem['number'];

                // 集数统计数自增
                if (array_key_exists($countPendingItem['episode_id'], $countData['episodes'])) {
                    $countData['episodes'][$countPendingItem['episode_id']]['total'] += $countPendingItem['number'];
                } else {
                    $countData['episodes'][$countPendingItem['episode_id']] = [
                        'total' => $countPendingItem['number'],
                        'step_category' => [],
                        'step' => []
                    ];
                }

                // 工序分类和工序统计自增
                if (!empty($categoryStepDataDict[$countPendingItem['step_id']])) {
                    $categoryStepId = $categoryStepDataDict[$countPendingItem['step_id']];

                    // 总计统计数
                    if (array_key_exists($categoryStepId, $countData['step_category'])) {
                        $countData['step_category'][$categoryStepId] += $countPendingItem['number'];
                    } else {
                        $countData['step_category'][$categoryStepId] = $countPendingItem['number'];
                    }

                    // 按集统计数
                    if (array_key_exists($categoryStepId, $countData['episodes'][$countPendingItem['episode_id']]['step_category'])) {
                        $countData['episodes'][$countPendingItem['episode_id']]['step_category'][$categoryStepId] += $countPendingItem['number'];
                    } else {
                        $countData['episodes'][$countPendingItem['episode_id']]['step_category'][$categoryStepId] = $countPendingItem['number'];
                    }
                }

                // 工序统计数自增
                if (array_key_exists($countPendingItem['step_id'], $countData['step'])) {
                    $countData['step'][$countPendingItem['step_id']] += $countPendingItem['number'];
                } else {
                    $countData['step'][$countPendingItem['step_id']] = $countPendingItem['number'];
                }

                // 工序按集统计数
                if (array_key_exists($countPendingItem['step_id'], $countData['episodes'][$countPendingItem['episode_id']]['step'])) {
                    $countData['episodes'][$countPendingItem['episode_id']]['step'][$countPendingItem['step_id']] += $countPendingItem['number'];
                } else {
                    $countData['episodes'][$countPendingItem['episode_id']]['step'][$countPendingItem['step_id']] = $countPendingItem['number'];
                }
            }
        }

        return $countData;
    }
}